export const formatDate = (
  date: Date | number | string,
  format: string = "YYYY-MM-DD HH:mm:ss"
): string => {
  let dateObj: Date;

  if (typeof date === "string") {
    // 兼容 iOS 日期格式，将 '-' 替换为 '/'
    date = date.replace(/-/g, "/");
    dateObj = new Date(date);
  } else if (typeof date === "number") {
    dateObj = new Date(date);
  } else {
    dateObj = date;
  }

  // 检查 Date 对象是否有效
  if (isNaN(dateObj.getTime())) {
    console.error("Invalid Date:", date);
    return "Invalid Date";
  }

  const padZero = (num: number) => (num < 10 ? "0" + num : num.toString());

  const replacements: { [key: string]: string } = {
    YYYY: dateObj.getFullYear().toString(),
    MM: padZero(dateObj.getMonth() + 1),
    DD: padZero(dateObj.getDate()),
    HH: padZero(dateObj.getHours()),
    mm: padZero(dateObj.getMinutes()),
    ss: padZero(dateObj.getSeconds()),
  };

  return format.replace(/YYYY|MM|DD|HH|mm|ss/g, (match) => replacements[match]);
};

// 获取当前日期时间
/**
 * getCurrentDateTime - 获取当前日期时间，并按指定格式返回。
 * @param format - 可选的日期时间格式，默认值为 "YYYY-MM-DD HH:mm:ss"。
 * @returns string - 当前日期时间的格式化字符串。
 *
 * 示例：
 * getCurrentDateTime(); // 返回 "2024-08-28 11:23:30"
 */
export const getCurrentDateTime = (format?: string): string => {
  const defaultFormat = "YYYY-MM-DD HH:mm:ss";
  return formatDate(new Date(), format || defaultFormat);
};

// 获取某天的开始时间 (00:00:00)
/**
 * getStartOfDay - 获取某天的开始时间，格式为 "YYYY-MM-DD 00:00:00"。
 * @param date - 要获取开始时间的日期，可以是 Date 对象、时间戳（number）或字符串。
 * @returns string - 开始时间的格式化字符串。
 *
 * 示例：
 * getStartOfDay("2024-08-28"); // 返回 "2024-08-28 00:00:00"
 */
export const getStartOfDay = (date: Date | number | string): string => {
  const d = new Date(date);
  d.setHours(0, 0, 0, 0);
  return formatDate(d);
};

// 获取某天的结束时间 (23:59:59)
/**
 * getEndOfDay - 获取某天的结束时间，格式为 "YYYY-MM-DD 23:59:59"。
 * @param date - 要获取结束时间的日期，可以是 Date 对象、时间戳（number）或字符串。
 * @returns string - 结束时间的格式化字符串。
 *
 * 示例：
 * getEndOfDay("2024-08-28"); // 返回 "2024-08-28 23:59:59"
 */
export const getEndOfDay = (date: Date | number | string): string => {
  const d = new Date(date);
  d.setHours(23, 59, 59, 999);
  return formatDate(d);
};

// 将时间戳转换为指定格式
/**
 * timestampToDate - 将时间戳转换为指定格式的日期字符串。
 * @param timestamp - 时间戳（毫秒数）。
 * @param format - 日期时间格式，默认值为 "YYYY-MM-DD HH:mm:ss"。
 * @returns string - 格式化后的日期字符串。
 *
 * 示例：
 * timestampToDate(1693218210000, "YYYY/MM/DD"); // 返回 "2024/08/28"
 */
export const timestampToDate = (
  timestamp: number,
  format: string = "YYYY-MM-DD HH:mm:ss"
): string => {
  return formatDate(new Date(timestamp), format);
};

// 将指定格式的日期转换为时间戳
/**
 * dateToTimestamp - 将指定格式的日期转换为时间戳。
 * @param date - 要转换的日期，可以是 Date 对象、时间戳（number）或字符串。
 * @returns number - 转换后的时间戳（毫秒数）。
 *
 * 示例：
 * dateToTimestamp("2024-08-28 11:23:30"); // 返回 1693218210000
 */
export const dateToTimestamp = (date: Date | number | string): number => {
  return new Date(date).getTime();
};

// 计算两个日期之间的天数
/**
 * daysBetween - 计算两个日期之间的天数。
 * @param startDate - 起始日期，可以是 Date 对象、时间戳（number）或字符串。
 * @param endDate - 结束日期，可以是 Date 对象、时间戳（number）或字符串。
 * @returns number - 两个日期之间的天数。
 *
 * 示例：
 * daysBetween("2024-08-28", "2024-09-05"); // 返回 8
 */
export const daysBetween = (
  startDate: Date | number | string,
  endDate: Date | number | string
): number => {
  const start = new Date(startDate).setHours(0, 0, 0, 0);
  const end = new Date(endDate).setHours(0, 0, 0, 0);
  return Math.floor((end - start) / (1000 * 60 * 60 * 24));
};

// 获取相对当前时间的描述 (例如：1小时前、昨天)
/**
 * getRelativeTime - 获取相对当前时间的描述，例如 "1小时前"、"昨天" 等。
 * @param date - 要转换的日期，可以是 Date 对象、时间戳（number）或字符串。
 * @returns string - 相对时间的描述字符串。
 *
 * 示例：
 * getRelativeTime("2024-08-28 10:00:00"); // 返回 "1 小时前"
 */
export const getRelativeTime = (date: Date | number | string): string => {
  const now = new Date();
  const diffMs = now.getTime() - new Date(date).getTime();
  const diffMinutes = Math.floor(diffMs / (1000 * 60));
  const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
  const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));

  if (diffMinutes < 60) {
    return `${diffMinutes} 分钟前`;
  } else if (diffHours < 24) {
    return `${diffHours} 小时前`;
  } else if (diffDays < 7) {
    return `${diffDays} 天前`;
  } else {
    return formatDate(date, "YYYY-MM-DD");
  }
};

// 获取当前日期前/后的指定天数的日期
/**
 * addDays - 获取指定日期前/后的指定天数的日期。
 * @param date - 要操作的日期，可以是 Date 对象、时间戳（number）或字符串。
 * @param days - 要添加或减少的天数，可以是正数（添加）或负数（减少）。
 * @param format - 日期格式，默认值为 "YYYY-MM-DD"。
 * @returns string - 操作后的日期字符串。
 *
 * 示例：
 * addDays("2024-08-28", 5); // 返回 "2024-09-02"
 */
export const addDays = (
  date: Date | number | string,
  days: number,
  format: string = "YYYY-MM-DD"
): string => {
  const d = new Date(date);
  d.setDate(d.getDate() + days);
  return formatDate(d, format);
};

// 验证日期格式是否有效
/**
 * isValidDate - 验证给定的日期格式是否有效。
 * @param date - 要验证的日期，可以是 Date 对象、时间戳（number）或字符串。
 * @returns boolean - 如果日期有效则返回 true，否则返回 false。
 *
 * 示例：
 * isValidDate("2024-08-28"); // 返回 true
 * isValidDate("Invalid-Date"); // 返回 false
 */
export const isValidDate = (date: Date | number | string): boolean => {
  const d = new Date(date);
  return !isNaN(d.getTime());
};

// 标准时间转为 yyyy-MM-dd
/**
 * parseDateString - 将标准日期字符串转换为 "YYYY-MM-DD" 格式。
 * @param dateStr - 标准的日期字符串。
 * @returns string - 转换后的 "YYYY-MM-DD" 日期字符串。
 *
 * 示例：
 * parseDateString("Wed Aug 21 2024 00:00:00 GMT+0800 (中国标准时间)"); // 返回 "2024-08-21"
 */
export const parseDateString = (dateStr: string): string => {
  const date = new Date(dateStr);

  if (isNaN(date.getTime())) {
    throw new Error("Invalid date format");
  }

  const padZero = (num: number) => (num < 10 ? "0" + num : num.toString());

  const year = date.getFullYear();
  const month = padZero(date.getMonth() + 1); // 月份从 0 开始
  const day = padZero(date.getDate());

  return `${year}-${month}-${day}`;
};

// 处理日期加减操作并格式化输出
/**
 * manipulateDate - 处理日期加减操作并格式化输出。
 * @param data - 传入的日期字符串，可以是 "YYYY-MM-DD hh:mm:ss"、"MM月DD日"、"YYYY-MM-DD" 等格式。如果没有年份，则默认使用当前年。
 * @param type - 操作类型，"add" 表示加天数，"minus" 表示减天数。
 * @param day - 要加或减的天数。
 * @returns string - 返回处理后的日期字符串，格式为 "YYYY-MM-DD"。
 *
 * 示例：
 * manipulateDate("08月21日", "add", 10); // 返回 "2024-08-31"
 * manipulateDate("2024-08-21 11:23:30", "minus", 5); // 返回 "2024-08-16"
 */
export const manipulateDate = (
  data: string,
  type: "add" | "minus",
  day: number
): string => {
  // 当前年份
  const currentYear = new Date().getFullYear();

  // 替换日期格式以兼容 iOS
  let formattedDate = data
    .replace(/(\d{1,2})月(\d{1,2})日/, `${currentYear}/$1/$2`) // 处理 "MM月DD日" 格式
    .replace(/-/g, "/"); // 将 "-" 替换为 "/"

  // 如果日期中不包含年份，则加上当前年份
  if (!/\d{4}/.test(formattedDate)) {
    formattedDate = `${currentYear}/${formattedDate}`;
  }

  let dateObj = new Date(formattedDate);

  // 检查日期是否有效
  if (isNaN(dateObj.getTime())) {
    console.error("Invalid Date:", formattedDate);
    return "Invalid Date";
  }

  // 根据 type 参数进行日期加减操作
  if (type === "add") {
    dateObj.setDate(dateObj.getDate() + day);
  } else if (type === "minus") {
    dateObj.setDate(dateObj.getDate() - day);
  }

  // 格式化返回的日期为 "YYYY-MM-DD" 格式
  const padZero = (num: number) => (num < 10 ? "0" + num : num.toString());
  const result = `${dateObj.getFullYear()}-${padZero(
    dateObj.getMonth() + 1
  )}-${padZero(dateObj.getDate())}`;

  return result;
};

// 导出所有模块
export default {
  formatDate,
  getCurrentDateTime,
  getStartOfDay,
  getEndOfDay,
  timestampToDate,
  dateToTimestamp,
  daysBetween,
  getRelativeTime,
  addDays,
  isValidDate,
  parseDateString,
  manipulateDate,
};